home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Utilities / Programming / Mac F2C 1.2.2 / Mac F2C Documentation / Cooperative Multitasking Mods < prev    next >
Encoding:
Text File  |  1995-08-17  |  12.7 KB  |  418 lines  |  [TEXT/MMCC]

  1. Mac F2C Users:
  2.  
  3. Mel Martinez spent a lot time figuring out how to add cooperative 
  4. multi-tasking to code generated by Mac F2C.  I had meant to incorporate his 
  5. changes directly into Mac F2C, but unfortunately the deadline for the CW7 
  6. CD pressing is here and I've been too busy with my "real" job to do it.
  7.  
  8. Rather than postpone this entirely until v1.3, I've decided to include 
  9. Mel's directions and so you can make the changes if it is important to you.  
  10. Below is the complete set of instructions Mel sent me (which he also posted 
  11. on c.s.m.p.*).  Please note that these modifications have not been tested 
  12. with THINK C or Symantec C.
  13.  
  14. I promise to fully test (MPW, THINK, Symantec, CW) and integrate Mel's 
  15. modifications in Mac F2C v1.3.  
  16.  
  17.     Igor
  18.     
  19.     
  20.     
  21.  
  22. From mem@eta.pha.jhu.edu Fri Jul 14 10:45:35 1995
  23. Date: Thu, 13 Jul 1995 16:24:51 -0500
  24. From: Mel Martinez <mem@eta.pha.jhu.edu>
  25. To: Igor Mikolic-Torreira <igormt@alumni.caltech.edu>,
  26.     mem@alumni.caltech.edu
  27. Newsgroups: comp.sys.mac.programmer.codewarrior,comp.sys.mac.scitech
  28. Subject: Multitasking with Mac F2C Fortran (improved!)
  29.  
  30. Hi y'all,
  31.  
  32. This posts describes how to add multitasking to Fortran code ported to the
  33. macintosh using Mac F2C and then MetroWerks C/C++ compiler.  The idea is
  34. that you may have some large legacy code to run, and it would be nice to
  35. be able to run it in the background on your mac.  For those porting
  36. Fortran using actual fortran compilers such as Absoft or Language Systems,
  37. I understand that those compilers have some options already in them for
  38. adding multitasking so I don't know if this is directly useful, but it
  39. should prove interesting.  This is version 2.0 of my presentation on this
  40. and is greatly improved over the first.
  41.  
  42. BTW:  I can't say enough about how nice of a job Mac F2C seems to do
  43. compiling FORTRAN to C.  Igor deserves a nice round of applause for his
  44. efforts (as well as the folks at Bell Labs).
  45.  
  46. Basically, we presume you have a FORTRAN project and you can compile it C
  47. successfully using Mac F2C and that you will then compile and execute it
  48. using MetroWerk's Codewarrior compiler using one of the Mac F2C-supplied
  49. project stationery setups.  I.E. this will be a SIOUX-based interface.
  50.  
  51. The goals are: to add calls to WaitNextEvent() at the proper rate
  52. throughout the code.  We also want the SIOUX interface to respond to user
  53. events like resizing the SIOUX window, updating the window in the
  54. background, and killing the process.  For decorative purposes, we also add
  55. a spinning cursor.  We also make use of the Time Manager to control our
  56. cpu SLICE time.  The Time manager provide microsecond timing (within 20
  57. microsec) and is much more accurate than using LMGetTicks (1/60th of a
  58. second).
  59.  
  60. Note - this code _should_ work with Think C as well, but I have not tested
  61. it.  Also, a THINK C version needs to add an event handler as this version
  62. just let's SIOUX handle user events.
  63.  
  64. There are two steps.
  65.  
  66. On the FORTRAN side, you need to insert calls to a routine.  In v1.0, I
  67. called it SPINCURSOR, since I was just trying to emulate the action of
  68. that routine under MPW C, however, To avoid confusion with the way
  69. SpinCursor actually behaves under Codewarrior, I now call it by what it
  70. does, DoMultiTask().  If you have made use of my previous version, just do
  71. a global replace.  Basically, insert the following line anywhere in your
  72. fortran code you think appropriate.  
  73.  
  74.        CALL DoMultiTask(SleepTime)
  75.  
  76. Try to get it in there atleast 60 times a second, a little more than this
  77. will not hurt at all.  Calling it 150 times a second will not hurt you
  78. very much, if at all.  SleepTime should be a long integer.  Use '1' or
  79. other small integer if you want a lot of cpu time, a larger number if your
  80. job is very leisurely.  This number represents the number of ticks (1/60th
  81. second) that your task is willing to surrender the processor context when
  82. in the background before being serviced again.
  83.  
  84. After this, go ahead and compile your fortran with Mac F2C.
  85.  
  86. Now, we want to open up the 'main.c' file that the Mac F2C project supplies
  87. and add a little code.  At the bottom of this post, I have appended the
  88. complete main.c file, so you can just grab and use that if you want to
  89. skip the following.
  90.  
  91. First, we need to include a few things and makes some declarations.   Near
  92. the top of the file add the following declarations:
  93.  
  94. #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
  95. #include <CursorCtl.h>  /*added 13-june-95 by M. E. Martinez*/
  96. #include <Events.h>
  97. #include <OSEvents.h>
  98. #include <OSUtils.h>
  99. #include <timer.h>
  100. #define       SLICE 16667     /*1/60th second in microseconds*/
  101. EventRecord   gmyEvent;       /*Holds event returned by OS*/
  102. TMTask        myTMT;          /*used for Time Manager calls*/
  103. long          delay, ohead;
  104. #endif /*Mac C compilers*/
  105.  
  106. #ifdef __MWERKS__    
  107. extern Boolean SIOUXQuitting;
  108. #endif
  109.  
  110.  
  111. If you already have some of these inclusions or declarations, be sure to
  112. address redundancies.  Note the SLICE parameter above is the control that
  113. sets exactly how often the program will actually call WaitNextEvent.  If
  114. you want to be less friendly and use more cpu time, increase this number. 
  115. This is the recommended rate though for assuring the user interaction is
  116. not affected (even QuickTime movies should still run fine in the
  117. foreground).
  118.  
  119. Next, we need to implement the following subroutine:
  120.  
  121. void domultitask_(long *sleepytime)
  122. {
  123. #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
  124.  RmvTime((QElemPtr)&myTMT);  /*check the time*/
  125.  if((delay+myTMT.tmCount - ohead)>SLICE)   /*has 1/60th second gone by?*/
  126.     {
  127.     SpinCursor(1); /*spin the cursor*/
  128.     if(WaitNextEvent(everyEvent, &gmyEvent, *sleepytime, NULL))
  129.       {
  130.       #if defined(__MWERKS__)               /*This is the extent of our*/
  131.       SIOUXHandleOneEvent(&gmyEvent);       /*event handler.  Add more */
  132.       if(SIOUXQuitting)exit(EXIT_FAILURE);  /*if you need to.          */
  133.       #endif
  134.       }
  135.     InsTime((QElemPtr)&myTMT);          /*restart timer*/
  136.     PrimeTime((QElemPtr)&myTMT,-delay);
  137.     }
  138. #endif /* Macintosh C compilers */
  139. }
  140.  
  141. Note carefully the lowercase and the underscore_ in the routine name -
  142. don't change this as that is how F2C translates the routine name.  The
  143. overhead for this call, if the branch is not taken, is less than a
  144. millisecond (the RmvTime call is 82 microseconds) on a 66 MHz PowerMac. 
  145. Compared to 1/60th of a second, this is tiny (less than 1 %) so you can
  146. afford to call this a little too often with no real impact on execution
  147. time.
  148.  
  149.  
  150. Finally, we have one small edit left.  We need to initialize our Time
  151. Manager entry.  Just after the program starts, a little after the main()
  152. call, but well before the MAIN() call that starts the FORTRAN code, put:
  153.  
  154. #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
  155.                            /* MEM 13-july-95 for doMultiTask() */
  156.    InitCursorCtl(nil);     /* initialize timer for doMultiTask() */
  157.    memset((void *)&myTMT, 0, sizeof(TMTask));
  158.    delay = 100*1000000;
  159.    InsTime((QElemPtr)&myTMT);
  160.    PrimeTime((QElemPtr)&myTMT,-delay);
  161. #endif /* Macintosh C compilers */
  162.  
  163. That's it!  Play with the SleepTime and SLICE parameters if you want, to
  164. see how they affect the cpu usage of your code, though the default SLICE
  165. value seems to work well.  I tend to set SleepTime to '1' myself and
  166. everything just hums along.  TaskIt! indicates that my app gets the vast
  167. majority of the cpu time in the background, even with about 12 other
  168. applications loaded, yet I feel no degradation in user responsiveness.
  169.  
  170. I welcome suggestions for improvements/corrections.  One possibility is
  171. passing both the SLICE and SleepTime parameters with the DoMultiTask()
  172. call, but I wanted to keep the implementation simple on the FORTRAN side
  173. (don't want to have to remember which parameter does what, since they take
  174. very different values).
  175.  
  176. I hope this is helpful.
  177.  
  178. Cheers,
  179.  
  180. Mel Martinez
  181. The Johns Hopkins University
  182. Dept. of Physics
  183. mem@jhu.edu
  184.  
  185.  
  186. /*===================main.c=============================*/
  187.  
  188. /* STARTUP PROCEDURE FOR UNIX FORTRAN PROGRAMS */
  189.  
  190. #include "stdio.h"
  191. #include "signal.h"
  192.  
  193. #ifndef SIGIOT
  194. #ifdef SIGABRT
  195. #define SIGIOT SIGABRT
  196. #endif
  197. #endif
  198.  
  199. #if defined(THINK_C) || defined(THINK_CPLUS)
  200. #include <console.h> /* IMT 2 Dec 94 Needed to make command line work
  201. under THINK */
  202. #endif
  203.  
  204. #ifdef __MWERKS__    /* IMT 2 Dec 94 Needed for MetroWerks (from Dirk
  205. Froehling) */
  206. #include <SIOUX.h>
  207. #endif
  208.  
  209. #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
  210. #include <CursorCtl.h>  /*added 13-june-95 by M. E. Martinez*/
  211. #include <Events.h>
  212. #include <OSEvents.h>
  213. #include <OSUtils.h>
  214. #include <timer.h>
  215. #define       SLICE 16667     /*1/60th second in microseconds*/
  216. EventRecord   gmyEvent;       /*Holds event returned by OS*/
  217. TMTask        myTMT;          /*used for Time Manager calls*/
  218. long          delay, ohead;
  219. #endif /*Mac C compilers*/
  220.  
  221. #ifdef __MWERKS__    
  222. extern Boolean SIOUXQuitting;
  223. #endif
  224.  
  225.  
  226.  
  227.  
  228. #ifndef KR_headers
  229. #include "stdlib.h"
  230. #endif
  231. #ifdef __cplusplus
  232. extern "C" {
  233. #endif
  234.  
  235. #ifdef NO__STDC
  236. #define ONEXIT onexit
  237. extern void f_exit();
  238. #else
  239. #ifndef KR_headers
  240. extern void f_exit(void);
  241. #ifndef NO_ONEXIT
  242. #define ONEXIT atexit
  243. extern int atexit(void (*)(void));
  244. #endif
  245. #else
  246. #ifndef NO_ONEXIT
  247. #define ONEXIT onexit
  248. extern void f_exit();
  249. #endif
  250. #endif
  251. #endif
  252.  
  253. #ifdef KR_headers
  254. extern void f_init(), sig_die();
  255. extern int MAIN__();
  256. #define Int /* int */
  257. #else
  258. extern void f_init(void), sig_die(char*, int);
  259. extern int MAIN__(void);
  260. #define Int int
  261. #endif
  262.  
  263. static void sigfdie(Int n)
  264. {
  265. sig_die("Floating Exception", 1);
  266. }
  267.  
  268.  
  269. static void sigidie(Int n)
  270. {
  271. sig_die("IOT Trap", 1);
  272. }
  273.  
  274. #ifdef SIGQUIT
  275. static void sigqdie(Int n)
  276. {
  277. sig_die("Quit signal", 1);
  278. }
  279. #endif
  280.  
  281.  
  282. static void sigindie(Int n)
  283. {
  284. sig_die("Interrupt", 0);
  285. }
  286.  
  287. static void sigtdie(Int n)
  288. {
  289. sig_die("Killed", 0);
  290. }
  291.  
  292. #ifdef SIGTRAP
  293. static void sigtrdie(Int n)
  294. {
  295. sig_die("Trace trap", 1);
  296. }
  297. #endif
  298.  
  299.  
  300. /* The following function written by Dirk Froehling; modified by IMT */
  301.  
  302. #if defined(THINK_C) || defined(THINK_CPLUS) 
  303.  
  304. #include <Files.h>
  305. #include <Processes.h>
  306.  
  307.  
  308. static void SetDefVolToAppVol(void)
  309. {
  310.    ProcessSerialNumber  currentPSN;
  311.    ProcessInfoRec    info;
  312.    FSSpec            appSpec;
  313.    
  314.    OSErr          err;
  315.         
  316.    currentPSN.highLongOfPSN = 0;
  317.    currentPSN.lowLongOfPSN = kCurrentProcess;
  318.    info.processInfoLength = sizeof(ProcessInfoRec);
  319.    info.processName = NULL;
  320.    info.processAppSpec = &appSpec;
  321.    err = GetProcessInformation(¤tPSN, &info);
  322.    err = HSetVol(NULL, appSpec.vRefNum, appSpec.parID);
  323. }
  324.  
  325. #endif
  326.  
  327. /*the following by MEM 13-july-95 for DoMultiTask() from FORTRAN (w/f2c) */
  328.        /* Now we add some cooperative multi-tasking here!*/
  329.             
  330. void domultitask_(long *sleepytime)
  331. {
  332. #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
  333.  RmvTime((QElemPtr)&myTMT);  /*check the time*/
  334.  if((delay+myTMT.tmCount - ohead)>SLICE)   /*has 1/60th second gone by?*/
  335.     {
  336.     SpinCursor(1); /*spin the cursor*/
  337.     if(WaitNextEvent(everyEvent, &gmyEvent, *sleepytime, NULL))
  338.       {
  339.       #if defined(__MWERKS__)               /*This is the extent of our*/
  340.       SIOUXHandleOneEvent(&gmyEvent);       /*event handler.  Add more */
  341.       if(SIOUXQuitting)exit(EXIT_FAILURE);  /*if you need to.          */
  342.       #endif
  343.       }
  344.     InsTime((QElemPtr)&myTMT);          /*restart timer*/
  345.     PrimeTime((QElemPtr)&myTMT,-delay);
  346.     }
  347. #endif /* Macintosh C compilers */
  348. }
  349.  
  350. int xargc;
  351. char **xargv;
  352.  
  353.  
  354. #ifdef KR_headers
  355. main(argc, argv) int argc; char **argv;
  356. #else
  357. main(int argc, char **argv)
  358. #endif
  359. {
  360.  
  361. #if defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__)
  362.  
  363.    argc = ccommand( &argv );     /* IMT 2 Dec 94 Think/Codewarrior mod */
  364.    InitCursorCtl(nil);           /* MEM 13-july-95 for doMultiTask() */
  365.                                    /* initialize timer for doMultiTask() */
  366.    memset((void *)&myTMT, 0, sizeof(TMTask));
  367.    delay = 100*1000000;
  368.    InsTime((QElemPtr)&myTMT);
  369.    PrimeTime((QElemPtr)&myTMT,-delay);
  370.  
  371. #endif /* Macintosh C compilers */
  372.  
  373. #if defined(THINK_C) || defined(THINK_CPLUS) 
  374.  
  375.    SetDefVolToAppVol();       /* IMT 14 Dec 94 Thanks to Dirk Froehling */
  376.  
  377. #endif /* Macintosh C compilers */
  378.  
  379. xargc = argc;
  380. xargv = argv;
  381. signal(SIGFPE, sigfdie);   /* ignore underflow, enable overflow */
  382. #ifdef SIGIOT
  383. signal(SIGIOT, sigidie);
  384. #endif
  385. #ifdef SIGTRAP
  386. signal(SIGTRAP, sigtrdie);
  387. #endif
  388. #ifdef SIGQUIT
  389. if(signal(SIGQUIT,sigqdie) == SIG_IGN)
  390.    signal(SIGQUIT, SIG_IGN);
  391. #endif
  392. if(signal(SIGINT, sigindie) == SIG_IGN)
  393.    signal(SIGINT, SIG_IGN);
  394. signal(SIGTERM,sigtdie);
  395.  
  396. #ifdef pdp11
  397.    ldfps(01200); /* detect overflow as an exception */
  398. #endif
  399.  
  400. f_init();
  401. #ifndef NO_ONEXIT
  402. ONEXIT(f_exit);
  403. #endif
  404.  
  405.             /*call the FORTRAN 'MAIN' program now*/
  406. MAIN__();
  407.  
  408. #ifdef NO_ONEXIT
  409. f_exit();
  410. #endif
  411. exit(0); /* exit(0) rather than return(0) to bypass Cray bug */
  412. return 0;   /* For compilers that complain of missing return values; */
  413.       /* others will complain that this is unreachable code. */
  414. }
  415. #ifdef __cplusplus
  416.    }
  417. #endif
  418.